import pandas as pd
import numpy as np
from collections import Counter
import math

# Step 1: Load the Iris dataset
url = "https://archive.ics.uci.edu/ml/machine-learning-databases/iris/iris.data"
column_names = ['sepal_length', 'sepal_width', 'petal_length', 'petal_width', 'class']
iris_data = pd.read_csv(url, header=None, names=column_names)

# Convert class labels to numerical values
iris_data['class'] = iris_data['class'].map({'Iris-setosa': 0, 'Iris-versicolor': 1, 'Iris-virginica': 2})

# Split the data into training and test sets
train_size = int(0.8 * len(iris_data))
train_data = iris_data.iloc[:train_size]
test_data = iris_data.iloc[train_size:]

def euclidean_distance(row1, row2):
    distance = 0.0
    for i in range(len(row1) - 1):
        distance += (row1[i] - row2[i]) ** 2
    return math.sqrt(distance)

def get_neighbors(train, test_row, num_neighbors):
    distances = list()
    for train_row in train.itertuples(index=False):
        dist = euclidean_distance(test_row, train_row)
        distances.append((train_row, dist))
    distances.sort(key=lambda x: x[1])
    neighbors = list()
    for i in range(num_neighbors):
        neighbors.append(distances[i][0])
    return neighbors

def predict_classification(train, test_row, num_neighbors):
    neighbors = get_neighbors(train, test_row, num_neighbors)
    output_values = [row[-1] for row in neighbors]
    prediction = max(set(output_values), key=output_values.count)
    return prediction

# Test the KNN algorithm on the test set
num_neighbors = 3
predictions = []
for _, test_row in test_data.iterrows():
    label = predict_classification(train_data, test_row.tolist(), num_neighbors)
    predictions.append(label)

# Evaluate the accuracy of the KNN classifier
actual_labels = test_data['class'].values.tolist()
accuracy = sum(1 for a, p in zip(actual_labels, predictions) if a == p) / len(actual_labels)
print(f'Accuracy of KNN classifier: {accuracy:.2f}')
